package sketch.main;

import java.util.LinkedList;
import java.util.List;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.internal.core.dom.NaiveASTFlattener;

import sketch.ast.ASTUtils;

//this class checks the validation of a test sketch
public final class TestSketchValidator {
	
	public final String source_file;
	
	public TestSketchValidator(String source_file) {
		this.source_file = source_file;
	}
	
	//error messages
	public String[] validate() {
		ValidationVisitor visitor = new ValidationVisitor();
		CompilationUnit unit = ASTUtils.astRoot(this.source_file);
		unit.accept(visitor);
		return (String[])visitor.error_messages.toArray(new String[0]);
	}
}

class ValidationVisitor extends NaiveASTFlattener {
	List<String> error_messages = new LinkedList<String>();
	
	@Override
	public boolean visit(MethodInvocation method) {
		if(this.isRandomSymbolicOrObserverDeclaration(method)) {
			if(this.insideLoop(method)) {
				error_messages.add("Error usage: " + method.toString() + ", inside a loop.");
			}
		}
		return super.visit(method);
	}
	
	private boolean insideLoop(MethodInvocation method) {
		boolean insideLoop = false;
		
		ASTNode parent = method.getParent();
		while(parent != null) {
			if(parent instanceof WhileStatement || parent instanceof DoStatement || parent instanceof EnhancedForStatement
					|| parent instanceof ForStatement) {
				insideLoop = true;
				break;
			}
			parent = parent.getParent();
		}
		
		return insideLoop;
	}
	
	private boolean isRandomSymbolicOrObserverDeclaration(MethodInvocation method) {
		String methodName = method.getName().getIdentifier();
		Expression expr = method.getExpression();
		if(expr == null) {
			return false;
		} else {
			String receiver_name = expr.toString();
			if((receiver_name.equals("Values") || receiver_name.equals("sketch.ounit.Values"))
					&& (methodName.startsWith("symbolic") || methodName.startsWith("random") || methodName.startsWith("randoop"))) {
				return true;
			}
			if((receiver_name.equals("Observer") || receiver_name.equals("sketch.ounit.Observer"))
					&& methodName.startsWith("observe") ) {
				return true;
			}
			return false;
		}
	}
}